package com.sangmo.fts.process.storage.service;

import com.sangmo.boot.framework.common.errors.ServiceException;
import com.sangmo.boot.framework.common.errors.StandardErrors;
import com.sangmo.boot.framework.common.session.UserSession;
import com.sangmo.boot.framework.common.utils.DateUtils;
import com.sangmo.boot.framework.data.filter.PageResult;
import com.sangmo.boot.framework.data.filter.PageSearch;
import com.sangmo.boot.framework.data.filter.ValueFilter;
import com.sangmo.boot.framework.data.idm.IdentityManager;
import com.sangmo.boot.framework.plugin.dataview.crud.service.DelegateViewService;
import com.sangmo.boot.framework.plugin.dataview.crud.service.ViewService;
import com.sangmo.fts.basic.model.Company;
import com.sangmo.fts.basic.service.CompanyService;
import com.sangmo.fts.common.utils.RandomUtils;
import com.sangmo.fts.process.inventory.interfaces.IfLoanAuditRequest;
import com.sangmo.fts.process.inventory.model.IfLoan;
import com.sangmo.fts.process.storage.interfaces.CsfLoanAuditRequest;
import com.sangmo.fts.process.storage.interfaces.CsfLoanDepositResponse;
import com.sangmo.fts.process.storage.interfaces.CsfLoanPayRequest;
import com.sangmo.fts.process.storage.model.CsfLoan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;

@Service
@Transactional
public class CsfLoanService extends DelegateViewService<CsfLoan> {

    @Autowired
    private CsfLoanEntityService csfLoanEntityService;

    @Autowired
    private IdentityManager identityManager;

    @Autowired
    private CompanyService companyService;

    @Override
    protected ViewService<CsfLoan> getEntityService() {
        return csfLoanEntityService;
    }

    public void accept(Long id) {
        CsfLoan loan = this.get(id);
        if (!CsfLoan.States.ACCEPTING.equals(loan.getState())) {
            throw new ServiceException(StandardErrors.EXTERNAL_ERROR.getStatus(), "error.csfLoan.accept.state.wrong");
        }
        loan.setState(CsfLoan.States.PENDING);
        loan.setAcceptCode(RandomUtils.generateRandomNum(10));
        this.save(loan);
    }

    public CsfLoanDepositResponse calcDeposit(Long id) {
        CsfLoan loan = this.get(id);
        Company company = companyService.get(loan.getApplyId());
        BigDecimal ratio = Company.rateMap.get(company.getCreditRating()+ "-" +loan.getDuration());
        BigDecimal deposit = loan.getAmount().multiply(ratio);
        CsfLoanDepositResponse response = new CsfLoanDepositResponse();
        response.setCreditRating(company.getCreditRating());
        response.setRatio(ratio);
        response.setDeposit(deposit);
        return response;
    }

    public void pay(Long id) {
        CsfLoan loan = this.get(id);
        if (null != loan.getRatio() && null != loan.getDeposit()) {
            throw new ServiceException(StandardErrors.EXTERNAL_ERROR.getStatus(), "error.csfLoan.pay.state.wrong");
        }
        Company company = companyService.get(loan.getApplyId());
        BigDecimal ratio = Company.rateMap.get(company.getCreditRating() + "-" + loan.getDuration());
        loan.setRatio(ratio);
        loan.setDeposit(loan.getAmount().multiply(ratio));
        this.save(loan);
    }

    public void audit(Long id, CsfLoanAuditRequest request) {
        CsfLoan loan = this.get(id);
        if (!IfLoan.States.PENDING.equals(loan.getState())) {
            throw new ServiceException(StandardErrors.CLIENT_ERROR.getStatus(), "error.csfLoan.audit.state.wrong");
        }
        loan.setAuditMind(request.getAuditMind());
        loan.setState(request.isPass()?IfLoan.States.CONFIRMED:IfLoan.States.REJECTED);
        if(request.isPass()) {
            loan.setCode(RandomUtils.generateRandomNum(10));
        }
        loan.setAuditBy((Long) UserSession.getUserInterface().getId());
        loan.setAuditTime(new Date());
        this.save(loan);
    }

    public PageResult<CsfLoan> assuranceSelection(PageSearch ps) {
        ps.getFilters().add(new ValueFilter("state", ValueFilter.OP_EQ, CsfLoan.States.PENDING));
        return super.search(ps);
    }

    public PageResult<CsfLoan> draftSelection(PageSearch ps) {
        ps.getFilters().add(new ValueFilter("state", ValueFilter.OP_EQ, CsfLoan.States.CONFIRMED));
        return super.search(ps);
    }

    public PageResult<CsfLoan> repaymentSelection(PageSearch ps) {
        ps.getFilters().add(new ValueFilter("state", ValueFilter.OP_EQ, CsfLoan.States.CONFIRMED));
        return super.search(ps);
    }

    public PageResult<CsfLoan> ladingBillSelection(PageSearch ps) {
        ps.getFilters().add(new ValueFilter("state", ValueFilter.OP_EQ, CsfLoan.States.CONFIRMED));
        ps.getFilters().add(new ValueFilter("settled", ValueFilter.OP_EQ, true));
        return super.search(ps);
    }

    public void settle(Long loanId, BigDecimal amount) {
        CsfLoan loan = this.get(loanId);
        if (loan.getAmount().compareTo(amount) <= 0) {
            loan.setSettled(true);
            this.save(loan);
        }
    }
}
